<?php
/**
 * @copyright  Copyright (c) 2010-2011 The Fajr authors (see AUTHORS).
 *             Use of this source code is governed by a MIT license that can be
 *             found in the LICENSE file in the project root directory.
 *
 * @package    Fajr
 * @subpackage Fajr
 * @author     Martin Sucha <anty.sk@gmail.com>
 * @filesource
 */
namespace fajr\config;

use Exception;
use libfajr\base\IllegalStateException;
use libfajr\base\Preconditions;
use fajr\config\ConfigUtils;
use fajr\util\FajrUtils;
use InvalidArgumentException;

/**
 * @package    Fajr
 * @subpackage Fajr
 * @author     Martin Sucha <anty.sk@gmail.com>
 */
class FajrConfig
{
  protected $config = null;

  protected static $parameterDescription = null;

  /**
   * Return description of configuration parameters
   *
   * This function caches its result so that it may be called
   * multiple times without performance overhead
   *
   * @returns array key=>
   *                 array('defaultValue'=>value, // if not present,
   *                                              // the param is required
   *                       'relativeTo'=>path, // for directories
   *                       'validator'=>validator // name of validator to use)
   * @see configuration.example.php for more information
   */
  protected static function getParameterDescription()
  {
    if (self::$parameterDescription === null) {
      self::$parameterDescription = FajrConfigOptions::getParameterDescription();
    }
    return self::$parameterDescription;
  }

  /**
   * Constructs FajrConfig
   *
   * @param array $configuration
   */
  public function __construct($configuration)
  {
    $parameters = self::getParameterDescription();

    $config = ConfigUtils::parseAndValidateConfiguration($parameters, $configuration);
    foreach ($config['AIS2.ServerList'] as $key => $server) {
      if ($key !== $server->getServerName()) {
        throw new Exception("Nesedí meno servera v konfiguracii AIS2.ServerList");
      }
    }
    $this->config = $config;
  }

  /**
   * Get a value of a given key
   * @param string $key
   * @returns mixed value of a given key
   * @throws InvalidArgumentException if the key does not exist
   */
  public function get($key)
  {
    Preconditions::checkIsString($key);
    // Note: isset() returns false if the item value is null
    if (!array_key_exists($key, $this->config)) {
      throw new InvalidArgumentException('Unknown configuration parameter: ' .
                                         $key);
    }
    return $this->config[$key];
  }

  /**
   * Get a directory configuration path.
   *
   * If a relative path is given in configuration, it is resolved
   * relative to the specified directory or project root directory
   * if no directory was specified
   *
   * @param string $key
   * @returns string absolute path for the directory specified in configuration
   *                 or null if this option was not specified and does not have
   *                 a default value
   * @see FajrConfig::getParameterDescription()
   * @see configuration.example.php
   */
  public function getDirectory($key)
  {
    $dir = $this->get($key);
    if ($dir === null) {
      return null;
    }
    if (FajrUtils::isAbsolutePath($dir)) {
      return $dir;
    }
    // default resolve relative
    $relativeTo = FajrUtils::getProjectRootDirectory();

    $parameters = $this->getParameterDescription();

    assert(array_key_exists($key, $parameters));

    $param = $parameters[$key];

    if (array_key_exists('relativeTo', $param)) {
      $relativeTo = $this->getDirectory($param['relativeTo']);
    }
    return FajrUtils::joinPath($relativeTo, $dir);
  }
}
